package com.huiquan.vocab.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

import com.huiquan.dyad.domain.DyadPre;
import com.huiquan.foundation.util.BusinessUtil;
import com.huiquan.framework.utils.CollectionUtil;
import com.huiquan.vocab.domain.SymptomCheckResult;
import com.huiquan.vocab.domain.VocabDyadRemove;

public class SymptomCheck {

	private String ruleFilePath = "./";
	private Map<String, List<String>> ruleMap = new HashMap<>();
	private Map<String, String> oInSRemoveMap = new HashMap<>();
	private Map<String, String> synonymOMap = new HashMap<>();
	private List<List<String>> oOaRemoveArrayList = new ArrayList<>();
	private List<List<String>> oOaRemoveResultList = new ArrayList<>();
	private Map<String, Map<String, String>> replaceMap;
	private Set<String> deDecorateO;
	private Map<String, Map<String, String>> odeMap;
	private Map<String, Map<String, String>> ooMap;
	private Map<String, Map<String, String>> synonymyMap;
	private List<VocabDyadRemove> oOaRemove;
	private List<VocabDyadRemove> oInSRemove;
	private List<String> wrongPPList;
	private List<Map<String, String>> poMergeRoles;

	/**
	 * 默认规则位置为jar包当前位置
	 */
	public SymptomCheck() {
		super();

		// 获取所有规则数据
		initRule();
	}

	/**
	 * 传入规则放置的位置
	 * 
	 * @param path
	 */
	public SymptomCheck(String path) {
		super();

		ruleFilePath = path;

		// 获取所有规则数据
		initRule();
	}

	/**
	 * 获取同义词~同义词o ,oa若判定为相同,属性可以忽略
	 * 
	 * @return
	 * @throws IOException
	 */
	private Map<String, Map<String, String>> getSynonmyMap(BufferedReader ruleBr) throws IOException {
		// 忽略o 和 oa的同义词,如果他们两个相同的话
		String line = "";
		Map<String, Map<String, String>> synonymyMap = new HashMap<>();
		while ((line = ruleBr.readLine()) != null) {
			String[] lines = line.split((char) 1 + "");
			String property = lines[0];
			String word = lines[1];
			String std = lines[2];
			if (synonymyMap.get(property) != null) {
				synonymyMap.get(property).put(word, std);
			} else {
				Map<String, String> syn = new HashMap<>();
				syn.put(word, std);
				synonymyMap.put(property, syn);
			}
		}
		return synonymyMap;
	}

	/**
	 * 获取remove规则
	 * 
	 * @return
	 * @throws IOException
	 */
	private List<VocabDyadRemove> getRemoveRule(BufferedReader ruleBr) throws IOException {
		// 忽略o 和 oa的同义词,如果他们两个相同的话
		String line = "";
		List<VocabDyadRemove> remove = new ArrayList<>();
		while ((line = ruleBr.readLine()) != null) {
			String[] lines = line.split((char) 1 + "");
			String array = lines[0];
			String partPattern = lines[1];
			String resultArr = lines[2];
			String resultPattern = lines[3];
			String type = lines[4];
			VocabDyadRemove re = new VocabDyadRemove();
			re.setArray(array);
			re.setPartPattern(partPattern);
			re.setResultArray(resultArr);
			re.setResultPattern(resultPattern);
			re.setType(type);
			remove.add(re);
		}
		return remove;
	}
    public static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }
	private Map<String, Map<String, String>> getODeMap(BufferedReader ruleBr) throws IOException {
		// 查询所有的o+de二元组
		List<Map<String, String>> odeAll = new ArrayList<>();
		String line = "";
		while ((line = ruleBr.readLine()) != null) {
			Map<String, String> ode = new HashMap<>();
			String[] lines = line.split((char) 1 + "");
			ode.put("array", lines[0]);
			ode.put("std", lines[1]);
			ode.put("part_pattern", lines[2]);
			ode.put("flag", lines[3]);
			ode.put("combine_s", lines[4]);
			odeAll.add(ode);
		}
		Map<String, Map<String, String>> rtn = new HashMap<>();
		for (Map<String, String> ode : odeAll) {
			rtn.put(ode.get("array") + "-" + ode.get("part_pattern"), ode);
		}
		return rtn;
	}

	/**
	 * 查找错误的p+p
	 * 
	 * @return
	 * @throws IOException
	 */
	private List<String> getWrongPP(BufferedReader ruleBr) throws IOException {
		List<String> de = new ArrayList<>();
		;
		String line = "";
		while ((line = ruleBr.readLine()) != null) {
			de.add(line);
		}
		return de;
	}

	/**
	 * 查找可以修饰o的de
	 * 
	 * @return
	 * @throws IOException
	 */
	private Set<String> getDeDecorateO(BufferedReader ruleBr) throws IOException {
		Set<String> de = new HashSet<>();
		String line = "";
		while ((line = ruleBr.readLine()) != null) {
			de.add(line);
		}
		return de;
	}

	/**
	 * 获取替换和拆分词语的map
	 * 
	 * @return
	 * @throws IOException
	 */
	private Map<String, Map<String, String>> getReplaceMap(BufferedReader ruleBr) throws IOException {
		Map<String, Map<String, String>> replaceMap = new HashMap<>();
		String line = "";
		while ((line = ruleBr.readLine()) != null) {
			String[] split = line.split((char) 1 + "");
			String[] original = split[0].split("\t");
			String result = split[1];
			if (replaceMap.get(original[1]) == null) {
				Map<String, String> value = new HashMap<>();
				value.put(original[0], result);
				replaceMap.put(original[1], value);
			} else {
				Map<String, String> value = replaceMap.get(original[1]);
				value.put(original[0], result);
			}
		}
		return replaceMap;
	}

	/**
	 * 从文件中获取规则
	 */
	private void initRule() {
		// 规则名称数组
		final String[] ruleArray = new String[] { "p_o_black", "p_o_merge", "s_de_black", "si_de_black", "o_de_black",
				"de_decorate_o", "o_in_s_black", "in_s_black", "o_oa_remove", "o_in_s_remove", "o_o_black",
				"multi_o_combine_s", "o_s_black", "synonym_o", "element_replace_split", "de_decorate_o2", "o_de_dyad",
				"o_o_right_dyad", "synonymy", "o_oa_remove2", "o_in_remove", "p_p_wrong", "p_o_merge2","o_in_black","r_black" };

		// 将规则对应的列表放入map中，remove规则和同义词O需要特殊处理，这些规则在之后的校验中使用
		BufferedReader ruleBr = null;
		File ruleFile = null;
		String line = "";
		for (String ruleName : ruleArray) {
			String filePath = ruleFilePath + ruleName + ".txt";
			ruleFile = new File(filePath);
			if (ruleFile.exists()) {

				try {
					ruleBr = createBufferedReaderByPath(ruleFilePath + ruleName + ".txt");

					if (ruleName.equals("o_oa_remove")) {
						while ((line = ruleBr.readLine()) != null) {
							if (!line.isEmpty() && line.indexOf("\t") > -1) {
								// o+oa的remove用分词的第一个词语做为key分流

								List<String> array = Arrays.asList(line.split("\t")[0].substring(1).split(","));
								List<String> result = Arrays.asList(line.split("\t")[1].substring(1).split(","));

								oOaRemoveArrayList.add(array);
								oOaRemoveResultList.add(result);
							}
						}
					} else if (ruleName.equals("o_in_s_remove")) {
						while ((line = ruleBr.readLine()) != null) {
							if (!line.isEmpty() && line.indexOf("\t") > -1) {
								oInSRemoveMap.put(line.split("\t")[0], line.split("\t")[1]);
							}
						}
					} else if (ruleName.equals("synonym_o")) {
						while ((line = ruleBr.readLine()) != null) {
							if (!line.isEmpty() && line.indexOf("\t") > -1) {
								synonymOMap.put(line.split("\t")[0], line.split("\t")[1]);
							}
						}
					} else if (ruleName.equals("element_replace_split")) {
						// 获取替换词语和替换属性Map
						replaceMap = getReplaceMap(ruleBr);
					} else if (ruleName.equals("de_decorate_o2")) {
						// 可以修饰o的de
						deDecorateO = getDeDecorateO(ruleBr);
					} else if (ruleName.equals("o_de_dyad")) {
						// 获取所有的o+de二元组
						odeMap = getODeMap(ruleBr);
					} else if (ruleName.equals("o_o_right_dyad")) {
						// 获取所有的o+o二元组,可以用o+de的抽取方法
						ooMap = getODeMap(ruleBr);
					} else if (ruleName.equals("synonymy")) {
						// 获取同义词对应map
						synonymyMap = getSynonmyMap(ruleBr);
					} else if (ruleName.equals("o_oa_remove2")) {
						// 获取o+oa remove规则
						oOaRemove = getRemoveRule(ruleBr);
					} else if (ruleName.equals("o_in_remove")) {
						// 获取'o+in' remove规则
						oInSRemove = getRemoveRule(ruleBr);
					} else if (ruleName.equals("p_p_wrong")) {
						// 查找错误的p+p
						wrongPPList = getWrongPP(ruleBr);
					} else if (ruleName.equals("p_o_merge2")) {
						// p+o合并规则
						poMergeRoles = getPOMerge(ruleBr);
					} else {
						List<String> list = new ArrayList<>();
						while ((line = ruleBr.readLine()) != null) {
							list.add(line);
						}

						ruleMap.put(ruleName, list);
					}

					ruleBr.close();
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					try {
						ruleBr.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			} else {
				System.out.println("规则文件缺失：" + filePath);
				returnMsg += "规则文件缺失：" + filePath + "\n";
			}
		}
	}

	private List<Map<String, String>> getPOMerge(BufferedReader ruleBr) throws IOException {
		List<Map<String, String>> poMerge = new ArrayList<>();
		String line = "";
		while ((line = ruleBr.readLine()) != null) {
			Map<String, String> po = new HashMap<>();
			String[] lines = line.split((char) 1 + "");
			po.put("id", lines[0]);
			po.put("array", lines[1]);
			po.put("std", lines[2]);
			po.put("part_pattern", lines[3]);
			poMerge.add(po);
		}
		return poMerge;
	}

	String tempO, tempS, tempSi, tempP, tempPOInS, tempInS, tempPOMerge;
	List<String> oOVocabList, oVocabList, oPropretyList, deList, de4OList, oSVocabList, oSPropertyList;
	boolean hasIn;
	private String returnMsg = "";
	private String returnKey = "";

	private void initTempParam() {
		tempO = "";
		tempS = "";
		tempSi = "";
		tempP = "";
		tempPOInS = "";
		tempInS = "";
		tempPOMerge = "";
		oOVocabList = new ArrayList<>();
		oVocabList = new ArrayList<>();
		oPropretyList = new ArrayList<>();
		deList = new ArrayList<>();
		de4OList = new ArrayList<>();
		oSVocabList = new ArrayList<>();
		oSPropertyList = new ArrayList<>();
		hasIn = false;
		returnMsg = "";
		returnKey = "";
	}

	/**
	 * 二元组校验症状
	 * 
	 * @param symptom
	 *            症状分词与属性，用“\t”分隔，例：颈部,正中,上方,肿块, ,o,p,p,s,
	 * 
	 * @return SymptomCheckResult类，包含症状正误标志和错误信息
	 */
	public SymptomCheckResult check(String symptom) {

		initTempParam();

		if (!returnMsg.isEmpty()) {
			return SymptomCheckResultUtil.wrong("file", returnMsg);
		}

		/**
		 * <pre>
		 * 二元组校验症状
		 * p+o：
		 *     需要连续提取的，所以在循环症状分词时直接校验。
		 *     p - 需要将连续的连续的p组合在临时变量中，例：,颈部,正中,上方,肿块,( ,o,p,p,s,)，在循环到第二个及第三个词时将临时变量组合成（正中,上方,）
		 *     o - 分多种情况
		 *        1、,颈部,正中,上方,肿块,( ,o,p,p,s,)，这时之前的循环到o之前没有p和o则只需要将o记录在临时变量中
		 * 
		 * </pre>
		 */
		SymptomCheckResult checkParam = checkParam(symptom);
		String newSymptom = symptom.split("\t")[0];
		String newPartPattern = symptom.split("\t")[1];
		if (checkParam.getFlag()) {
			// r和ra单独抽取处理
			Map<String,String> rtn = checkRRa(newSymptom,newPartPattern);
			if(rtn != null){
				// 成功
				if(rtn.get("code")!=null &&"200".equals(rtn.get("code"))){
					newSymptom = rtn.get("symptom");
					newPartPattern = rtn.get("partpattern");
				}
			}

			// 获取症状的分词和属性
			String[] array = newSymptom.substring(1).split(",");
			String[] partPattern = newPartPattern.substring(1).split(",");

			// 拆分症状，根据各个二元组来校验正误
			for (int i = 0; i < partPattern.length; i++) {
				if (partPattern[i].equals("p")) {
					// 只需要维护临时变量p
					tempP += array[i] + ",";

					tempPOInS += array[i] + ",";
				} else if (partPattern[i].indexOf("o") > -1) {

					// 校验p+o，如果p+o是错误的则直接可以返回错误；记录所有的o之后在o+o校验中使用
					if (tempO.isEmpty() && !tempP.isEmpty()) {
						// 之前没有o只有p
						String pO = "," + tempP + array[i] + ",";
						if (ruleMap.get("p_o_black").contains(pO)) {
							return SymptomCheckResultUtil.wrong("p+o 1", pO);
						}
						// 如果和p可以合并则维护进临时变量tempPOMerge
						setTempPOMergeByCurrentO(pO);

					} else if (!tempO.isEmpty() && tempP.isEmpty()) {
						// 之前没有p只有o
						setOVocabListByPo();
					} else if (!tempO.isEmpty() && !tempP.isEmpty()) {
						// 之前有p也有o
						String fullPCurrentO = "," + tempP + array[i] + ",";
						String fullPPrevO = "," + tempO + "," + tempP;

						if (!ruleMap.get("p_o_black").contains(fullPCurrentO)) {
							// 将上一个o添加入o列表中
							setOVocabListByPo();

							// 如果和p可以合并则维护进临时变量tempPOMerge
							setTempPOMergeByCurrentO(fullPCurrentO);

						} else if (!ruleMap.get("p_o_black").contains(fullPPrevO)) {
							// 如果所有p和上一个o组合为正确，将o或p+o组合放入o列表
							if (ruleMap.get("p_o_merge").contains(fullPPrevO.replace(",", ""))) {
								oOVocabList.add(fullPPrevO.replace(",", ""));

								oSVocabList.add(fullPPrevO.replace(",", ""));
							} else {
								setOVocabListByPo();
							}

							tempPOMerge = "";
						} else {
							// 如果p需要拆分开和两个o分担
							boolean flag = false;
							String[] pArray = tempP.split(",");

							// 如果p的个数只有一个则不需要拆分直接错误了
							if (pArray.length < 2) {
								return SymptomCheckResultUtil.wrong("p+o 3", tempO + fullPCurrentO);
							}

							String currentPO = tempP + array[i] + ",";
							String prevPO = "," + tempO;
							for (int j = 0; j < pArray.length; j++) {
								prevPO += "," + pArray[j];
								currentPO = currentPO.substring(pArray[j].length() + 1);
								if (!ruleMap.get("p_o_black").contains(prevPO + ",")
										&& !ruleMap.get("p_o_black").contains("," + currentPO)) {
									// 处理上一个o，如果能合并成po组合则合并后加入列表
									if (ruleMap.get("p_o_merge").contains(prevPO.replace(",", ""))) {
										oOVocabList.add(prevPO.replace(",", ""));

										oSVocabList.add(prevPO.replace(",", ""));
									} else {
										setOVocabListByPo();
									}

									// 如果和p可以合并则维护进临时变量tempPOMerge
									setTempPOMergeByCurrentO("," + currentPO);

									flag = true; // 记录下已经找到匹配的白名单
									break;
								}
							}
							// 如果所有组合都没有正确的po组合，则返回错误
							if (!flag) {
								return SymptomCheckResultUtil.wrong("p+o 3", fullPCurrentO);
							}
						}
					}

					oSPropertyList.add(partPattern[i]);
					oPropretyList.add(partPattern[i]);
					tempO = array[i];
					oVocabList.add(array[i]);
					tempPOInS += array[i] + ",";
					tempP = "";

				} else {
					// p+o如果之前存在需要处理
					SymptomCheckResult scr = checkFullPPrevO();
					if (!scr.getFlag()) {
						return scr;
					}

				}
			}

			// p+o如果之前存在需要处理
			SymptomCheckResult scr = checkFullPPrevO();
			if (!scr.getFlag()) {
				return scr;
			}
			List<DyadPre> dyadList = new ArrayList<>();
			try {
				// 抽取二元组
				dyadList = getDyadBySymptom(newSymptom, newPartPattern);

			}catch (Exception e){
				return SymptomCheckResultUtil.wrong("", e.getMessage());

			}

			// 校验其他
			checkDyad(dyadList);
			if (isBlank(returnKey) && isBlank(returnMsg)) {
				return SymptomCheckResultUtil.right();
			} else {
				return SymptomCheckResultUtil.wrong(returnKey, returnMsg);
			}
		} else {
			return checkParam;
		}
	}

	/**
	 * 	校验r和ra正误
	 * @param symptom
	 * @param partpattern
	 * @return
	 */
	private Map<String,String> checkRRa(String symptom, String partpattern) {
		// 获取连续的r或者ra
		String[] array = symptom.substring(1).split(",");
		String[] partPattern = partpattern.substring(1).split(",");
		StringBuilder rRaTemp = new StringBuilder();
		Map<String,String > rtn = new HashMap<>();
		List<String> rRa = new ArrayList<>();
		StringBuilder newSymptom = new StringBuilder();
		StringBuilder newPartpattern = new StringBuilder();
		newSymptom.append(",");
		newPartpattern.append(",");
		for(int i=0;i<array.length;i++){
			if("r".equals(partPattern[i])|| "ra".equals(partPattern[i])){
				rRaTemp.append(array[i]);
			}else{
				rRa.add(rRaTemp.toString());
				rRaTemp = new StringBuilder();
				newSymptom.append(array[i]).append(",");
				newPartpattern.append(partPattern[i]).append(",");
			}
		}
		if(rRaTemp.length()>0){
			rRa.add(rRaTemp.toString());
		}

		List<String> rRaBlackRuleList = ruleMap.get("r_black");
		// 根据黑名单过滤r和ra的组合
		if(rRaBlackRuleList != null && rRaBlackRuleList.size()>0){
			for(String r:rRa){
				if(rRaBlackRuleList.contains(r)){
					rtn.put("code","500");
					rtn.put("msg","R或RA是错误的组合"+r);
					return rtn;
				}
			}
		}
		rtn.put("code","200");
		rtn.put("symptom",newSymptom.toString());
		rtn.put("partpattern",newPartpattern.toString());
		return rtn;

	}

	private boolean checkDyad(List<DyadPre> dyadList) {
		for(DyadPre dyad:dyadList){
			String array = dyad.getArray();
			String partPattern = dyad.getPartPattern();
			String type = dyad.getType();
			// de - o+de - s+de 该二元组的s+de若是错误的则二元组是错误的(o+de只是带走de~不能判断症状正误)
			if("s+de".equals(type)){
				// 判断二元组是否在黑名单中
				checkDyadInBlack("s+de",array,partPattern);
			}
			// si+de 错误就错误
			if("si+de".equals(type)){
				// 判断二元组是否在黑名单中
				checkDyadInBlack("si+de",array,partPattern);
			}
			// o+in 错误就错误
			if("o+in".equals(type)){
				// 判断二元组是否在黑名单中
				checkDyadInBlack("o+in",array,partPattern);
			}
			// in+s 错误就错误
			if("in+s".equals(type)){
				// 判断二元组是否在黑名单中
				checkDyadInBlack("in+s",array,partPattern);
			}
			// o+o 错误症状就错误
			if("o+o".equals(type)){
				// 判断二元组是否在黑名单中
				checkDyadInBlack("o+o",array,partPattern);
			}
			// o+s 错误则错误
			if("o+s".equals(type)){
				// 判断二元组是否在黑名单中
				checkDyadInBlack("o+s",array,partPattern);
			}
			// p+o在之前已经判断过
			
		}
		return false;
	}

	private void checkDyadInBlack(String type, String array, String partPattern) {
		// TODO Auto-generated method stub
		List<String> ruleList = new ArrayList<>();
		if("s+de".equals(type)){
			ruleList = ruleMap.get("s_de_black");
		}else if("si+de".equals(type)){
			ruleList = ruleMap.get("si_de_black");
		}else if("o+in".equals(type)){
			ruleList = ruleMap.get("o_in_black");
			if(ruleList.contains(array+"\t"+partPattern)){
				setReturnInfo(type, array);
			}
		}else if("in+s".equals(type)){
			ruleList = ruleMap.get("in_s_black");
		}else if("o+o".equals(type)){
			ruleList = ruleMap.get("o_o_black");
			if(ruleList.contains(array+"\t"+partPattern)){
				setReturnInfo(type, array);
			}
		}else if("o+s".equals(type)){
			ruleList = ruleMap.get("o_s_black");
			if(ruleList.contains(array+"\t"+partPattern)){
				setReturnInfo(type, array);
			}
		}
		if(ruleList.contains(array)){
			setReturnInfo(type, array);
		}
	}


	private void setReturnInfo(String type, String msg) {
		returnKey = type;
		returnMsg = msg;
	}


	private void setOVocabListByPo() {
		if (!tempPOMerge.isEmpty()) {
			oOVocabList.add(tempPOMerge);

			oSVocabList.add(tempPOMerge);
		} else if (!tempO.isEmpty()) {
			oOVocabList.add(tempO);

			oSVocabList.add(tempO);
		}
	}

	private void setTempPOMergeByCurrentO(String pO) {
		if (ruleMap.get("p_o_merge").contains(pO)) {
			tempPOMerge = pO.replace(",", "");
		} else {
			tempPOMerge = "";
		}
	}

	private SymptomCheckResult checkFullPPrevO() {
		if (tempO.isEmpty() && !tempP.isEmpty()) {
			return SymptomCheckResultUtil.wrong("p+o 4", tempP);

		} else if (!tempO.isEmpty() && !tempP.isEmpty()) {
			String fullPPrevO = "," + tempO + "," + tempP;
			if (!ruleMap.get("p_o_black").contains(fullPPrevO)) {
				// 如果所有p和上一个o组合为正确，将o或p+o组合放入o列表
				if (ruleMap.get("p_o_merge").contains(fullPPrevO.replace(",", ""))) {
					tempPOMerge = fullPPrevO.replace(",", "");
				}
				setOVocabListByPo();

			} else {
				return SymptomCheckResultUtil.wrong("p+o 5", fullPPrevO);
			}
		} else if (!tempO.isEmpty()) {
			setOVocabListByPo();
		}

		tempPOMerge = "";
		tempO = "";
		tempP = "";
		return SymptomCheckResultUtil.right();
	}

	/**
	 * 校验传入的参数：不能为空、有分隔符、分词和属性个数相同
	 * 
	 * @param symptom
	 * @return
	 */
	private SymptomCheckResult checkParam(String symptom) {
		// 不能为空
		if (symptom == null || symptom.isEmpty()) {
			System.out.println("症状校验失败，参数不能为空！");
			return SymptomCheckResultUtil.wrong("param", "症状校验失败，参数不能为空！");
		}

		// 有分隔符
		String[] arrayAndProperty = symptom.split("\t");
		if (arrayAndProperty.length < 2) {
			System.out.println("症状校验失败，参数没有正确的分隔符：" + symptom);
			return SymptomCheckResultUtil.wrong("param", "症状校验失败，参数没有正确的分隔符！");
		}

		// 分词和属性个数相同
		if (arrayAndProperty[0].split(",").length != arrayAndProperty[1].split(",").length) {
			System.out.println("症状校验失败，分词与属性个数不相等：" + symptom);
			return SymptomCheckResultUtil.wrong("param", "症状校验失败，分词与属性个数不相等！");
		}

		return SymptomCheckResultUtil.right();
	}

	/**
	 * 通过文件路径来构造BufferedReader
	 * 
	 * @param path
	 * @return
	 * @throws IOException
	 */
	private static BufferedReader createBufferedReaderByPath(String path) throws IOException {

		return new BufferedReader(new InputStreamReader(new FileInputStream(new File(path)), "utf-8"));

	}


	/**
	 * 根据单条症状抽取二元组
	 * 
	 * @return
	 */
	private List<DyadPre> getDyadBySymptom(String array, String partPattern) throws Exception {
		// 存放抽取出来的二元组
		List<DyadPre> dyadList = new ArrayList<>();

		String[] wordArray = array.substring(1).split(",");
		String[] partPatternArray = partPattern.substring(1).split(",");
		List<DyadPre> side = new ArrayList<>();
		List<DyadPre> oDe = new ArrayList<>();
		List<DyadPre> sde = new ArrayList<>();
		List<DyadPre> pp = new ArrayList<>();
		List<DyadPre> po = new ArrayList<>();
		List<DyadPre> oo = new ArrayList<>();
		List<DyadPre> oIn = new ArrayList<>();
		List<DyadPre> oS = new ArrayList<>();
		List<DyadPre> inS = new ArrayList<>();

		// 获取二元组元素对应的标准词
		String[] std = null;
		// 处理替换词语和替换属性
		Map<String, String> replaceResult = replaceVocab(replaceMap, wordArray, partPatternArray);
		if (replaceResult != null && replaceResult.size() > 0) {
			array = replaceResult.get("array");
			partPattern = replaceResult.get("partPattern");
			wordArray = array.substring(1).split(",");
			partPatternArray = partPattern.substring(1).split(",");
		}
		// 维护好二元组分词的同义词标准词
		std = getStdArray(wordArray, partPatternArray, synonymyMap);

		// 抽取si+de单个和多个都抽取
		if (checkProperty(partPattern, "si,de")) {
			side = extractDe("si", wordArray, partPatternArray);
			dyadList.addAll(side);
		}
		// o+de直接抽取多个 能被o带走的de
		if (checkProperty(partPattern, "o,de")) {
			oDe = extractODe(wordArray, partPatternArray, deDecorateO, std);
			dyadList.addAll(oDe);
		}
		// s+de 除去已经判断修饰o的de,再抽取s+de (先要抽取单个de,再抽取多个进行校验(抽取时,全部抽取在之后进行校验))
		if (checkProperty(partPattern, "s,de")) {
			sde = extractSDe(wordArray, partPatternArray, oDe, odeMap, synonymyMap.get("de"));
			dyadList.addAll(sde);
		}

		// p+p 连续抽取整个p,p,p
		if (checkProperty(partPattern, "p")) {
			pp = extractP(wordArray, partPatternArray);
			dyadList.addAll(pp);
		}

		// 抽取p+o,相邻的p相邻的p+(单独o)或(单独o)+p
		if (checkProperty(partPattern, "p,o")) {
			po = extractPO(wordArray, partPatternArray, std, wrongPPList);
			dyadList.addAll(po);

			// p+o抽取完后p+o合并成o(同时拥有按合成结果)
			// 合并完把std转变为二元组的std为了合并同义词
			Map<String, String> mergeResult = mergePO(array, partPattern, std, poMergeRoles);
			if (mergeResult != null && mergeResult.size() > 0) {
				array = mergeResult.get("array");
				partPattern = mergeResult.get("partPattern");
				wordArray = array.substring(1).split(",");
				partPatternArray = partPattern.substring(1).split(",");
				std = mergeResult.get("std").substring(1).split(",");
			}
		}

		// 保存还剩下o的下标
		List<Integer> oWordIndex = new ArrayList<>();
		// o+o抽取症状中所有的o
		// 抽取o+o 如果抽取的o+o 只有一个o 就用这个o抽取o+s
		if (checkProperty(partPattern, "o")) {
			oo = extractOO(wordArray, partPatternArray, synonymyMap, oWordIndex, oOaRemove, std);
			// 如果 还剩多个o就加入二元组校验
			if (oo != null && oo.size() > 0) {
				String[] arr = oo.get(0).getArray().substring(1).split(",");
				if (arr.length > 1) {
					// 加入二元组校验
					dyadList.addAll(oo);
				}
			}
		}

		// in 不抽取(需要remove)
		if (checkProperty(partPattern, "in")) {
			// 有o+oa 经过remove了
			if (oo != null && oo.size() > 0) {
				oIn = extractOIn(wordArray, partPatternArray, synonymyMap, oo.get(0), oWordIndex, oInSRemove, std);
				dyadList.addAll(oIn);
			}
			// 抽取in+s
			if (checkProperty(partPattern, "in,s")) {
				inS = extractInS(wordArray, partPatternArray);
				dyadList.addAll(inS);
			}
		}

		// o+s抽取 根据正确的o+o的核心词抽取o+s
		if (checkProperty(partPattern, "s")) {
			// 有o+o 经过remove了
			if (oo != null && oo.size() > 0) {
				String[] arr = oo.get(0).getArray().substring(1).split(",");
				// 有o+o需要经过核心词判断
				if (arr.length > 1) {
					// 没有校验过o+o的核心词的不抽取,错误的o+o也不抽取o+s
					oS = extractOS(wordArray, partPatternArray, synonymyMap, oo.get(0), oWordIndex, ooMap, std);
				} else {
					// 只有一个o 直接抽取o+s
					oS = extractOS(wordArray, partPatternArray, oo.get(0), oWordIndex, std);
				}
				dyadList.addAll(oS);
			}
		}
		// o+s中单独的si也要抽取到o+s中
		if (partPattern.contains("si")) {
			for (int i = 0; i < partPatternArray.length; i++) {
				if ("si".equals(partPatternArray[i])) {
					DyadPre pre = new DyadPre();
					pre.setArray("," + wordArray[i] + ",");
					pre.setPartPattern("," + partPatternArray[i] + ",");
					pre.setStdArray("," + std[i] + ",");
					pre.setType("o+s");
					dyadList.add(pre);
				}
			}
		}
		return dyadList;
	}
	
	/**
	 * 直接抽取in+s
	 * 
	 * @param wordArray
	 * @param partPatternArray
	 * @return
	 */
	private List<DyadPre> extractInS(String[] wordArray, String[] partPatternArray) {
		List<String> inSArray = new ArrayList<>();
		List<String> inSPartPattern = new ArrayList<>();
		List<DyadPre> rtn = new ArrayList<>();
		for (int i = 0; i < wordArray.length; i++) {
			if ("in".equals(partPatternArray[i]) || "s".equals(partPatternArray[i])) {
				inSArray.add(wordArray[i]);
				inSPartPattern.add(partPatternArray[i]);
			}
		}
		DyadPre pre = new DyadPre();
		pre.setArray(BusinessUtil.getStringFromListBySeparator(inSArray, ","));
		pre.setPartPattern(BusinessUtil.getStringFromListBySeparator(inSPartPattern, ","));
		pre.setType("in+s");
		rtn.add(pre);
		return rtn;
	}

	/**
	 * 多个o 需要经过o+o的核心词校验,若o+o是错误的二元组则不抽取o+s ,若是正确的o+o则根据核心词抽取, 若o+o未校验,则不抽取o+s
	 * 
	 * @param wordArray
	 * @param partPatternArray
	 * @param synonymyMap
	 * @param DyadPre
	 * @param oWordIndex
	 * @param ooMap
	 * @return
	 */
	private List<DyadPre> extractOS(String[] wordArray, String[] partPatternArray,
			Map<String, Map<String, String>> synonymyMap, DyadPre oo, List<Integer> oWordIndex,
			Map<String, Map<String, String>> ooMap, String[] std) {
		List<DyadPre> rtn = new ArrayList<>();
		// o在原症状下的下标
		if (oo != null && oWordIndex != null && oWordIndex.size() > 0) {
			// o+o是全部抽取,所以只有一条
			String ooArray = oo.getArray();
			String ooPartPattern = oo.getPartPattern();
			String ooStd = oo.getStdArray();

			// 如果已校验该组o+o会直接到标准词下,所以不需要进行元素标准词处理.
			if (ooMap.get(ooArray + "-" + ooPartPattern) != null) {
				// 已校验的o+o 找到核心词
				Map<String, String> ooKeyWord = ooMap.get(ooArray + "-" + ooPartPattern);
				String[] ooStdArr = ooKeyWord.get("array").substring(1).split(",");
				String[] ooStdFlag = ooKeyWord.get("combine_s").substring(1).split(",");
				// 获取核心词 从最后一个开始匹配
				List<Integer> combineSIndex = new ArrayList<>();
				// 记录下核心词的位置
				for (int i = (ooStdArr.length - 1); i >= (ooStdArr.length - ooStdFlag.length); i--) {
					if ("1".equals(ooStdFlag[i - (ooStdArr.length - ooStdFlag.length)])) {
						combineSIndex.add(i);
					}
				}
				List<String> oSArray = new ArrayList<>();
				List<String> oSPartPattern = new ArrayList<>();
				List<String> oSStd = new ArrayList<>();

				// 二元组o+o的词
				String[] oArray = ooArray.substring(1).split(",");
				String[] oPartPattern = ooPartPattern.substring(1).split(",");
				String[] oStd = ooStd.substring(1).split(",");
				// 抽取o+s
				outter: for (int i = 0; i < wordArray.length; i++) {
					// 添加o 和 oa remove后的结果
					for (int j = 0; j < oWordIndex.size(); j++) {
						// 判断该位置是不是remove留下的o
						if (i == oWordIndex.get(j)) {
							// 判断该位置是不是核心词
							if (combineSIndex.contains(j)) {
								oSArray.add(oArray[j]);
								oSPartPattern.add(oPartPattern[j]);
								oSStd.add(oStd[j]);
								continue outter;
							}
						}
					}
					if ("s".equals(partPatternArray[i])) {
						oSArray.add(wordArray[i]);
						oSPartPattern.add(partPatternArray[i]);
						oSStd.add(std[i]);
					}
				}
				DyadPre pre = new DyadPre();
				pre.setArray(BusinessUtil.getStringFromListBySeparator(oSArray, ","));
				pre.setPartPattern(BusinessUtil.getStringFromListBySeparator(oSPartPattern, ","));
				pre.setStdArray(BusinessUtil.getStringFromListBySeparator(oSStd, ","));
				pre.setType("o+s");
				rtn.add(pre);
				return rtn;
			} else {
				// oo没有校验或者为错误的二元组,不抽取o+s
				return rtn;
			}
		}

		return rtn;
	}

	/**
	 * 单个o抽取o+s
	 * 
	 * @param wordArray
	 * @param partPatternArray
	 * @param synonymyMap
	 * @param DyadPre
	 * @param oWordIndex
	 * @return
	 */
	private List<DyadPre> extractOS(String[] wordArray, String[] partPatternArray, DyadPre DyadPre,
			List<Integer> oWordIndex, String[] std) {
		List<DyadPre> rtn = new ArrayList<>();
		// 根据o+oa remove结果替换症状中的o
		String[] oArray = DyadPre.getArray().substring(1).split(",");
		String[] oPartPattern = DyadPre.getPartPattern().substring(1).split(",");
		String[] oStd = DyadPre.getStdArray().substring(1).split(",");

		List<String> oSArray = new ArrayList<>();
		List<String> oSPartPattern = new ArrayList<>();
		List<String> oSStd = new ArrayList<>();

		outter: for (int i = 0; i < wordArray.length; i++) {
			// 添加o 和 oa remove后的结果
			for (int j = 0; j < oWordIndex.size(); j++) {
				if (i == oWordIndex.get(j)) {
					oSArray.add(oArray[j]);
					oSPartPattern.add(oPartPattern[j]);
					oSStd.add(oStd[j]);
					continue outter;
				}
			}
			if ("s".equals(partPatternArray[i])) {
				oSArray.add(wordArray[i]);
				oSPartPattern.add(partPatternArray[i]);
				oSStd.add(std[i]);
			}
		}
		DyadPre pre = new DyadPre();
		pre.setArray(BusinessUtil.getStringFromListBySeparator(oSArray, ","));
		pre.setPartPattern(BusinessUtil.getStringFromListBySeparator(oSPartPattern, ","));
		pre.setStdArray(BusinessUtil.getStringFromListBySeparator(oSStd, ","));
		pre.setType("o+s");
		rtn.add(pre);
		return rtn;
	}

	private String[] getStdArray(String[] wordArray, String[] partPatternArray,
			Map<String, Map<String, String>> synonymyMap) throws Exception {
		List<String> std = new ArrayList<>();
		for (int i = 0; i < wordArray.length; i++) {
			if(synonymyMap.get(partPatternArray[i]) != null){
				std.add(synonymyMap.get(partPatternArray[i]).get(wordArray[i]) != null
						? synonymyMap.get(partPatternArray[i]).get(wordArray[i]) : wordArray[i]);
			}else{
				throw new Exception("存在二元组未知属性，不能用二元组判断正误");
			}
		}
		return std.toArray(new String[0]);
	}

	private List<DyadPre> extractOIn(String[] wordArray, String[] partPatternArray,
			Map<String, Map<String, String>> synonymyMap, DyadPre DyadPre, List<Integer> oWordIndex,
			List<VocabDyadRemove> oInSRemove, String[] std) {
		// 根据o+oa remove结果替换症状中的o
		String[] oArray = DyadPre.getArray().substring(1).split(",");
		String[] oPartPattern = DyadPre.getPartPattern().substring(1).split(",");
		String[] oStd = DyadPre.getStdArray().substring(1).split(",");

		List<String> oInSArray = new ArrayList<>();
		List<String> oInSPartPattern = new ArrayList<>();
		List<String> oInSStd = new ArrayList<>();

		outter: for (int i = 0; i < wordArray.length; i++) {
			// 添加o 和 oa remove后的结果
			for (int j = 0; j < oWordIndex.size(); j++) {
				if (i == oWordIndex.get(j)) {
					oInSArray.add(oArray[j]);
					oInSPartPattern.add(oPartPattern[j]);
					oInSStd.add(oStd[j]);
					continue outter;
				}
			}
			if ("in".equals(partPatternArray[i])) {
				oInSArray.add(wordArray[i]);
				oInSPartPattern.add(partPatternArray[i]);
				oInSStd.add(std[i]);
			}
		}
		// 获取o+in remove规则
		Map<String, String> rtn = dealRemove(BusinessUtil.getStringFromListBySeparator(oInSArray, ","),
				BusinessUtil.getStringFromListBySeparator(oInSPartPattern, ","), oInSRemove, synonymyMap, oWordIndex,
				BusinessUtil.getStringFromListBySeparator(oInSStd, ","));
		List<DyadPre> pres = new ArrayList<>();
		if (rtn != null && rtn.size() > 0) {
			DyadPre pre = new DyadPre();
			pre.setPartPattern(rtn.get("partPattern"));
			pre.setArray(rtn.get("array"));
			pre.setStdArray(rtn.get("std"));
			pre.setRemoveArray(rtn.get("remove_array") != null ? rtn.get("remove_array") : "");
			pre.setRemoveRa(rtn.get("remove_ra") != null ? rtn.get("remove_ra") : "");
			pre.setRemoveRp(rtn.get("remove_rp") != null ? rtn.get("remove_rp") : "");
			pre.setType("o+in");
			if(pre.getPartPattern().contains("o") && pre.getPartPattern().contains("in")) {
				pres.add(pre);
			}
		}
		return pres;
	}

	/**
	 * 抽取o+o 抽取完后进行remove
	 * 
	 * @param wordArray
	 * @param partPatternArray
	 * @param oOaRemove
	 * @return
	 */
	private List<DyadPre> extractOO(String[] wordArray, String[] partPatternArray,
			Map<String, Map<String, String>> synonymy, List<Integer> oWordIndex, List<VocabDyadRemove> oOaRemove,
			String[] std) {
		List<String> ooList = new ArrayList<>();
		List<String> ooPartList = new ArrayList<>();
		List<String> ooStdList = new ArrayList<>();

		for (int i = 0; i < wordArray.length; i++) {
			if ("oa".equals(partPatternArray[i]) || "o".equals(partPatternArray[i])) {
				ooList.add(wordArray[i]);
				ooPartList.add(partPatternArray[i]);
				ooStdList.add(std[i]);
				oWordIndex.add(i);
			}
		}

		List<DyadPre> pres = new ArrayList<>();
		// 大于1个o的时候需要进行remove
		if (ooList.size() > 1) {
			Map<String, String> rtn = dealRemove(BusinessUtil.getStringFromListBySeparator(ooList, ","),
					BusinessUtil.getStringFromListBySeparator(ooPartList, ","), oOaRemove, synonymy, oWordIndex,
					BusinessUtil.getStringFromListBySeparator(ooStdList, ","));
			if (rtn != null && rtn.size() > 0) {
				DyadPre pre = new DyadPre();
				pre.setPartPattern(rtn.get("partPattern"));
				pre.setArray(rtn.get("array"));
				pre.setStdArray(rtn.get("std"));
				pre.setRemoveArray(rtn.get("remove_array") != null ? rtn.get("remove_array") : "");
				pre.setRemoveRa(rtn.get("remove_ra") != null ? rtn.get("remove_ra") : "");
				pre.setRemoveRp(rtn.get("remove_rp") != null ? rtn.get("remove_rp") : "");
				pre.setType("o+o");
				pres.add(pre);
			}
		} else {
			DyadPre pre = new DyadPre();
			pre.setPartPattern(BusinessUtil.getStringFromListBySeparator(ooPartList, ","));
			pre.setArray(BusinessUtil.getStringFromListBySeparator(ooList, ","));
			pre.setStdArray(BusinessUtil.getStringFromListBySeparator(ooStdList, ","));

			pres.add(pre);
		}
		return pres;
	}
	
    public static boolean equals(String str1, String str2) {
        return str1 == null ? str2 == null : str1.equals(str2);
    }
	/**
	 * 根据类型和remove规则进行remove remove 属性不能间隔
	 * 
	 * @param type
	 * @param ooList
	 * @param ooPartList
	 * @param firstRemoveList
	 */
	private Map<String, String> dealRemove(String array, String partPattern, List<VocabDyadRemove> firstRemoveList,
			Map<String, Map<String, String>> synonymy, List<Integer> oWordIndex, String std) {
		Map<String, String> rtn = new HashMap<>();
		String tempArray = "";
		String tempPartPattern = "";

		// 经过规则合并后没有变化了出循环
		while (!equals(tempArray, array) && !equals(tempPartPattern, partPattern)) {
			// 记录进循环时的分词和属性
			tempArray = array;
			tempPartPattern = partPattern;

			// 进行规则循环合并
			for (VocabDyadRemove remove : firstRemoveList) {
				String[] wordArray = array.substring(1).split(",");
				String[] partPatternArray = partPattern.substring(1).split(",");
				String[] stdArray = std.substring(1).split(",");
				String[] removeArray = remove.getArray().substring(1).split(",");
				String[] removePartPattern = remove.getPartPattern().substring(1).split(",");
				String[] resultArray = remove.getResultArray().substring(1).split(",");
				String[] resultPattern = remove.getResultPattern().substring(1).split(",");
				// 获取remove匹配到的词语的下标
				List<Integer> removeIndex = new ArrayList<>();
				int j = 0;
				boolean beginFlag = false;
				// 如果规则数组小于等于症状数组才进行处理
				if (wordArray.length >= removeArray.length) {
					// 循环获取匹配上的下标
					remove: for (int i = 0; i < removeArray.length;) {
						for (; j < wordArray.length; j++) {
							// 元素同义词的标准词相同
							// o ,oa 忽略属性
							if (("oa".equals(removePartPattern[i]) || "o".equals(removePartPattern[i]))
									&& "oa".equals(partPatternArray[j]) || "o".equals(partPatternArray[j])) {
								if (equals(
										synonymy.get(partPatternArray[j]).get(wordArray[j]) == null ? wordArray[j]
												: synonymy.get(partPatternArray[j]).get(wordArray[j]),
										synonymy.get(removePartPattern[i]).get(removeArray[i]) == null ? removeArray[i]
												: synonymy.get(removePartPattern[i]).get(removeArray[i]))) {
									removeIndex.add(j);
									j++;
									beginFlag = true;
									break;
								} else {
									// 不相同则重新开始
									if (beginFlag) {
										beginFlag = false;
										i = 0;
										continue remove;
									}
								}

							} else {
								// 如果不是o和oa则需要比较属性
								if (removePartPattern[i].equals(partPatternArray[j]) && equals(
										synonymy.get(partPatternArray[j]).get(wordArray[j]) == null ? wordArray[j]
												: synonymy.get(partPatternArray[j]).get(wordArray[j]),
										synonymy.get(removePartPattern[i]).get(removeArray[i]) == null ? removeArray[i]
												: synonymy.get(removePartPattern[i]).get(removeArray[i]))) {
									removeIndex.add(j);
									j++;
									beginFlag = true;
									break;
								} else {
									// 不相同则重新开始
									if (beginFlag) {
										beginFlag = false;
										i = 0;
										continue remove;
									}
								}
							}
						}
						i++;
					}
				}
				// 规则匹配成功
				if (removeArray.length == removeIndex.size()) {
					// 记录remove规则和结果和属性
					if (rtn.get("remove_array") != null && rtn.get("remove_ra") != null
							&& rtn.get("remove_rp") != null) {
						rtn.put("remove_array", rtn.get("remove_array") + BusinessUtil
								.getStringFromListBySeparator(CollectionUtil.getListByArray(removeArray), ",") + "|");
						rtn.put("remove_ra", rtn.get("remove_ra") + BusinessUtil
								.getStringFromListBySeparator(CollectionUtil.getListByArray(resultArray), ",") + "|");
						rtn.put("remove_rp", rtn.get("remove_rp") + BusinessUtil
								.getStringFromListBySeparator(CollectionUtil.getListByArray(resultPattern), ",") + "|");
					} else {
						rtn.put("remove_array", BusinessUtil
								.getStringFromListBySeparator(CollectionUtil.getListByArray(removeArray), ",") + "|");
						rtn.put("remove_ra", BusinessUtil
								.getStringFromListBySeparator(CollectionUtil.getListByArray(resultArray), ",") + "|");
						rtn.put("remove_rp", BusinessUtil
								.getStringFromListBySeparator(CollectionUtil.getListByArray(resultPattern), ",") + "|");
					}

					List<String> wordList = CollectionUtil.getListByArray(wordArray);
					List<String> partPatternList = CollectionUtil.getListByArray(partPatternArray);
					List<String> stdList = CollectionUtil.getListByArray(stdArray);

					// 找到被remove掉的词
					int k = 0;
					List<Integer> removeWordIndex = new ArrayList<>();
					for (int i = 0; i < removeArray.length; i++) {
						if (k < resultArray.length) {
							if (!removeArray[i].equals(resultArray[k])) {
								removeWordIndex.add(i);
							} else {
								k++;
							}
						} else {
							removeWordIndex.add(i);
						}
					}
					int m = 0;
					// 替换属性
					for (int i = 0; i < removeIndex.size(); i++) {
						// 不是remove的词进行属性替换
						if (!removeWordIndex.contains(i)) {
							partPatternList.set((int) removeIndex.get(i), resultPattern[m]);
							m++;
						}
					}
					// remove该词
					for (int i = (removeWordIndex.size() - 1); i >= 0; i--) {
						wordList.remove((int) removeIndex.get((int) removeWordIndex.get(i)));
						partPatternList.remove((int) removeIndex.get((int) removeWordIndex.get(i)));
						stdList.remove((int) removeIndex.get((int) removeWordIndex.get(i)));
						// 如果是o+in+s的remove保留o的index用于o+s抽取 , o+oa
						// remove时候remove o
						if (!remove.getType().contains("in")) {
							oWordIndex.remove((int) removeIndex.get((int) removeWordIndex.get(i)));
						}
						removeWordIndex.remove(i);
					}
					array = BusinessUtil.getStringFromListBySeparator(wordList, ",");
					partPattern = BusinessUtil.getStringFromListBySeparator(partPatternList, ",");
					std = BusinessUtil.getStringFromListBySeparator(stdList, ",");
				}
			}
		}
		rtn.put("array", array);
		rtn.put("partPattern", partPattern);
		rtn.put("std", std);

		return rtn;
	}
	
	/**
	 * 抽取s+de 除去已经判断修饰o的de,再抽取s+de
	 * 
	 * @param wordArray
	 * @param partPatternArray
	 * @param ode
	 * @param odeMap
	 * @return
	 */
	private List<DyadPre> extractSDe(String[] wordArray, String[] partPatternArray, List<DyadPre> odeList,
			Map<String, Map<String, String>> odeMap, Map<String, String> deSynonmy) {
		List<DyadPre> rtn = new ArrayList<>();
		if (odeList != null && odeList.size() > 0) {
			// o+de是全部抽取,所以只有一条
			String oDeArray = odeList.get(0).getArray();
			String oDePartPattern = odeList.get(0).getPartPattern();

			// 存在o+de的情况,就必须先判断完o+de ,再抽取s+de不然不抽取
			// 判断是否属性和词语都一样
			if (odeMap.get(oDeArray + "-" + oDePartPattern) != null) {
				// 已校验的o+de 看看已经使用了的de
				Map<String, String> ode = odeMap.get(oDeArray + "-" + oDePartPattern);
				// 如果flag= 0 正确 ---> 所有的o和de都能被带走
				String flag = ode.get("flag");
				String[] dePart = ode.get("part_pattern").substring(1).split(",");
				String[] deArray = ode.get("array").substring(1).split(",");
				String[] deFlag = ode.get("combine_s").substring(1).split(",");

				String array = "";
				String partPattern = "";
				if (equals(flag, "0")) {
					// 都可以被带走
					// 去除被o带走的de
					Map<String, String> removeResult = removeDeByO(wordArray, partPatternArray,
							oDeArray.substring(1).split(","), oDePartPattern.substring(1).split(","));
					if (removeResult != null && removeResult.size() > 0) {
						array = removeResult.get("array");
						partPattern = removeResult.get("partPattern");
					}
				} else {
					// 有不能被带走的de
					// 根据标准词查找可以带走的de
					List<String> deS = new ArrayList<>();
					List<String> deSPart = new ArrayList<>();
					for (int i = 0; i < wordArray.length; i++) {
						if ("de".equals(partPatternArray[i]) || "s".equals(partPatternArray[i])) {
							deS.add(wordArray[i]);
							deSPart.add(partPatternArray[i]);
						}
					}
					// 可以被带走的下标
					TreeSet<Integer> deSIndex = new TreeSet<Integer>();
					// 循环可以被带走的de的元素标准词
					for (int i = 0; i < deArray.length; i++) {
						if ("de".equals(dePart[i]) && "1".equals(deFlag[i])) {
							// 循环记录被带走的下标
							for (int j = 0; j < deS.size(); j++) {
								// 标准词进行比较
								if (equals(dePart[i], deSPart.get(j)) && equals(
										deSynonmy.get(deArray[i]) == null ? deArray[i] : deSynonmy.get(deArray[i]),
										deSynonmy.get(deS.get(j)) == null ? deS.get(j) : deSynonmy.get(deS.get(j)))) {
									deSIndex.add(j);
								}
							}
						}
					}
					for (int i = 0; i < deSIndex.size();) {
						int index = deSIndex.pollLast();
						deS.remove(index);
						deSPart.remove(index);
					}
					array = BusinessUtil.getStringFromListBySeparator(deS, ",");
					partPattern = BusinessUtil.getStringFromListBySeparator(deSPart, ",");
				}
				rtn = extractDe("s", array.substring(1).split(","), partPattern.substring(1).split(","));
			}
		} else {
			// 不存在o+de的情况全部抽取s+de
			rtn = extractDe("s", wordArray, partPatternArray);
		}
		return rtn;
	}

	private Map<String, String> removeDeByO(String[] wordArray, String[] partPatternArray, String[] oDeArray,
			String[] oDePartPattern) {
		TreeSet<Integer> removeIndex = new TreeSet<Integer>();
		for (int i = 0; i < oDeArray.length; i++) {
			for (int j = 0; j < wordArray.length; j++) {
				if (equals(wordArray[j], oDeArray[i])
						&& equals(partPatternArray[j], oDePartPattern[i])) {
					removeIndex.add(j);
					break;
				}
			}
		}
		List<String> wordList = CollectionUtil.getListByArray(wordArray);
		List<String> partPatternList = CollectionUtil.getListByArray(partPatternArray);
		for (int i = 0; i < removeIndex.size();) {
			int index = removeIndex.pollLast();
			wordList.remove(index);
			partPatternList.remove(index);
		}
		Map<String, String> rtn = new HashMap<>();
		rtn.put("array", BusinessUtil.getStringFromListBySeparator(wordList, ","));
		rtn.put("partPattern", BusinessUtil.getStringFromListBySeparator(partPatternList, ","));
		return rtn;
	}


	/**
	 * 抽取o+de 所有de与o 整个抽取 de,o,de,de,oa,de,s ----> de,o,de,de,oa,de
	 * 
	 * @param wordArray
	 * @param partPatternArray
	 * @return
	 */
	private static List<DyadPre> extractODe(String[] wordArray, String[] partPatternArray, Set<String> deDecorateO,
			String[] std) {
		List<String> deOArrayList = new ArrayList<>();
		List<String> deOPartList = new ArrayList<>();
		List<DyadPre> rtn = new ArrayList<>();
		DyadPre ode = new DyadPre();
		for (int i = 0; i < wordArray.length; i++) {
			if ("de".equals(partPatternArray[i])) {
				if (deDecorateO.contains(std[i])) {
					deOArrayList.add(wordArray[i]);
					deOPartList.add(partPatternArray[i]);
				}
			} else if ("o".equals(partPatternArray[i]) || "oa".equals(partPatternArray[i])) {
				deOArrayList.add(wordArray[i]);
				deOPartList.add(partPatternArray[i]);
			}
		}
		ode.setArray(BusinessUtil.getStringFromListBySeparator(deOArrayList, ","));
		ode.setPartPattern(BusinessUtil.getStringFromListBySeparator(deOPartList, ","));
		ode.setType("o+de");
		// 如果de都不能修饰o则没有o+de二元组
		if (deOPartList.contains("de") && (deOPartList.contains("o") || deOPartList.contains("oa"))) {
			rtn.add(ode);
		}
		return rtn;
	}

	/**
	 * 	 p+o抽取完后有替换元素和p+o合并成o(同时拥有按合成结果) 合并完把std转变为二元组的std为了合并同义词

	 * @param array
	 * @param partPattern
	 * @param std
	 * @param poMergeRoles
	 * @return
	 */
	private Map<String, String> mergePO(String array, String partPattern, String[] std,
			List<Map<String, String>> poMergeRoles) {
		String tempArray = "";
		String tempPartPattern = "";
		// 经过规则合并后没有变化了出循环
		while (!equals(tempArray, array) && !equals(tempPartPattern, partPattern)) {
			// 记录进循环时的分词和属性
			tempArray = array;
			tempPartPattern = partPattern;
			// 进行规则循环合并
			for (Map<String, String> poMergeRole : poMergeRoles) {
				String[] wordArray = array.substring(1).split(",");
				String[] partPatternArray = partPattern.substring(1).split(",");
				String[] poArray = poMergeRole.get("array").substring(1).split(",");
				String[] poPartPattern = poMergeRole.get("part_pattern").substring(1).split(",");
				List<Integer> oIndex = new ArrayList<>();
				List<Integer> pIndex = new ArrayList<>();
				int j = 0;
				boolean beginFlag = false;
				if (wordArray.length >= poArray.length) {
					outterLoop: for (int i = 0; i < poArray.length;) {
						for (; j < wordArray.length; j++) {
							if ("p".equals(partPatternArray[j])) {
								if (poPartPattern[i].equals(partPatternArray[j]) && poArray[i].equals(wordArray[j])) {
									pIndex.add(j);
									j++;
									beginFlag = true;
									break;
								} else {
									if (beginFlag) {
										beginFlag = false;
										i = 0;
										break outterLoop;
									}
								}
							} else if ("o".equals(partPatternArray[j]) || "oa".equals(partPatternArray[j])) {
								boolean oOaFlag = false;
								// o和oa不区分属性
								if (("o".equals(poPartPattern[i]) || "oa".equals(poPartPattern[i]))
										&& ("o".equals(partPatternArray[j]) || "oa".equals(partPatternArray[j]))) {
									oOaFlag = true;
								}
								if ((oOaFlag ? true : poPartPattern[i].equals(partPatternArray[j]))
										&& poArray[i].equals(wordArray[j])) {
									oIndex.add(j);
									j++;
									beginFlag = true;
									break;
								} else {
									if (beginFlag) {
										beginFlag = false;
										i = 0;
										continue outterLoop;
									}
								}
							}
						}
						i++;
					}
				}
				// 规则匹配成功
				if (oIndex.size() > 0 && pIndex.size() > 0 && poArray.length == (oIndex.size() + pIndex.size())) {
					List<String> wordList = CollectionUtil.getListByArray(wordArray);
					List<String> partPatternList = CollectionUtil.getListByArray(partPatternArray);
					List<String> stdList = CollectionUtil.getListByArray(std);
					// 把o下标的数据进行替换
					wordList.remove((int) oIndex.get(0));
					wordList.add((int) oIndex.get(0), poMergeRole.get("array").replace(",", ""));
					stdList.remove((int) oIndex.get(0));
					stdList.add((int) oIndex.get(0), poMergeRole.get("std").replace(",", ""));
					// 把p下标中的数据清空
					for (int i = (pIndex.size() - 1); i >= 0; i--) {
						wordList.remove((int) pIndex.get(i));
						partPatternList.remove((int) pIndex.get(i));
						stdList.remove((int) pIndex.get(i));
					}
					array = BusinessUtil.getStringFromListBySeparator(wordList, ",");
					partPattern = BusinessUtil.getStringFromListBySeparator(partPatternList, ",");
					std = BusinessUtil.getStringFromListBySeparator(stdList, ",").substring(1).split(",");
				}
			}
		}
		Map<String, String> rtn = new HashMap<>();
		rtn.put("array", array);
		rtn.put("partPattern", partPattern);
		rtn.put("std", BusinessUtil.getStringFromListBySeparator(CollectionUtil.getListByArray(std), ","));
		return rtn;
	}

	/**
	 * 根据词语的列表获取根据逗号分割的字符串
	 * 
	 * @param pTemp
	 * @return
	 */
	private String getWordStrByList(List<String> pTemp) {
		if (pTemp.isEmpty()) {
			return "";
		}

		StringBuilder sb = new StringBuilder(",");
		for (String p : pTemp) {
			sb.append(p);
			sb.append(",");
		}
		return sb.toString();
	}

	/**
	 * 根据p和o的词语以及相关属性获取最终p+o的数据
	 * 
	 * @param pTemp
	 * @param oTemp
	 * @param splitFlag
	 * @param position:1表示p在o之前；2表示p在o之后
	 * @param oStdTemp
	 * @param pStdTemp
	 * @return
	 */
	private List<DyadPre> getPOListByWords(List<String> pTemp, String oTemp, String oPropertyTemp, boolean splitFlag,
			int position, List<String> pStdTemp, String oStdTemp, List<String> wrongPPList) {
		List<String> ppStrList = new ArrayList<>();
		List<String> ppStdStrList = new ArrayList<>();

		if (!splitFlag || pTemp.size() == 1 || !wrongPPList.contains(getWordStrByList(pTemp))) {
			ppStrList.add(getWordStrByList(pTemp));
			ppStdStrList.add(getWordStrByList(pStdTemp));
		} else if (pTemp.size() > 1) {
			for (int i = 1; i <= pTemp.size(); i++) {
				if (position == 1) {
					ppStrList.add(getWordStrByList(pTemp.subList(pTemp.size() - i, pTemp.size())));
					ppStdStrList.add(getWordStrByList(pStdTemp.subList(pStdTemp.size() - i, pStdTemp.size())));
				} else {
					ppStrList.add(getWordStrByList(pTemp.subList(0, i)));
					ppStdStrList.add(getWordStrByList(pStdTemp.subList(0, i)));
				}
			}
		}

		List<DyadPre> resultList = new ArrayList<>();
		for (int i = 0; i < ppStrList.size(); i++) {
			String pp = ppStrList.get(i);
			String ppStd = ppStdStrList.get(i);

			DyadPre temp = new DyadPre();
			temp.setArray(position == 1 ? pp + oTemp + "," : "," + oTemp + pp);
			String partPattern = ",";
			for (int j = 0; j < pp.length() - pp.replace(",", "").length() - 1; j++) {
				partPattern += "p,";
			}
			temp.setPartPattern(position == 1 ? partPattern + oPropertyTemp + "," : "," + oPropertyTemp + partPattern);
			temp.setOrderVocabulary(oStdTemp);
			temp.setStdArray(position == 1 ? ppStd + oStdTemp + "," : "," + oStdTemp + ppStd);
			temp.setStdSynonym(temp.getStdArray());
			temp.setType("p+o");

			resultList.add(temp);
		}

		return resultList;
	}

	/**
	 * 根据一个复杂的p+o拆解出单个p+o的列表
	 * 
	 * @param wrongPPList
	 * @return
	 */
	private List<DyadPre> getPOPreByComplex(String[] words, String[] properties, String[] stds,
			List<String> wrongPPList) {

		List<DyadPre> list = new ArrayList<>();
		boolean splitFlag = false;
		List<String> pTemp = new ArrayList<>();
		List<String> pStdTemp = new ArrayList<>();
		String oTemp = "";
		String oStdTemp = "";
		String oPropertyTemp = "";

		for (int i = 0; i < words.length; i++) {
			if (properties[i].equals("p")) {
				// 属性是p的元素则累加，并判断该当前p+p是否是错误的
				pTemp.add(words[i]);
				pStdTemp.add(stds[i]);
				if (!splitFlag && wrongPPList.contains(getWordStrByList(pTemp))) {
					splitFlag = true;
				}

				// 如果p是最后一个词语了则需维护最后一个p+o
				if (i == words.length - 1) {
					list.addAll(
							getPOListByWords(pTemp, oTemp, oPropertyTemp, false, 2, pStdTemp, oStdTemp, wrongPPList));
				}
			} else if ("o".equals(properties[i]) || "oa".equals(properties[i])) {
				// 属性是o或者oa，如果有上一个o和p则先维护
				if (!oTemp.isEmpty() && !pTemp.isEmpty()) {
					list.addAll(getPOListByWords(pTemp, oTemp, oPropertyTemp, splitFlag, 2, pStdTemp, oStdTemp,
							wrongPPList));
				}

				// 如果p+p之前没有o，则多个p不需要拆分
				if (oTemp.isEmpty()) {
					splitFlag = false;
				}

				// 将属性修改为当前的o
				oTemp = words[i];
				oStdTemp = stds[i];
				oPropertyTemp = properties[i];

				// 如果之前有p则维护当前o的p+o
				if (!pTemp.isEmpty()) {
					list.addAll(getPOListByWords(pTemp, oTemp, oPropertyTemp, splitFlag, 1, pStdTemp, oStdTemp,
							wrongPPList));
				}

				// 维护好之后清空之前的p
				pTemp = new ArrayList<>();
				pStdTemp = new ArrayList<>();
				splitFlag = true;
			}
		}
		return list;
	}

	/**
	 * 抽取p+o,相邻的p相邻的p+(单独o)或(单独o)+p
	 * 
	 * @param wordArray
	 * @param partPatternArray
	 * @param wrongPPList
	 * @return
	 */
	private List<DyadPre> extractPO(String[] wordArray, String[] partPatternArray, String[] std,
			List<String> wrongPPList) {
		List<String> wordList = new ArrayList<>();
		List<String> propertyList = new ArrayList<>();
		for (int i = 0; i < wordArray.length; i++) {
			if ("p".equals(partPatternArray[i]) || "o".equals(partPatternArray[i])
					|| "oa".equals(partPatternArray[i])) {
				wordList.add(wordArray[i]);
				propertyList.add(partPatternArray[i]);
			}
		}
		// p+o通过代码拆分生成
		List<DyadPre> resultList = new ArrayList<>();
		resultList.addAll(getPOPreByComplex(wordList.toArray(new String[0]), propertyList.toArray(new String[0]), std,
				wrongPPList));
		return resultList;
	}

	/**
	 * 抽取连续的整个的p,p,p 二元组p+p
	 */
	private List<DyadPre> extractP(String[] wordArray, String[] partPatternArray) {
		List<String> wordList = new ArrayList<>();
		List<String> propertyList = new ArrayList<>();
		List<DyadPre> rtn = new ArrayList<>();
		for (int i = 0; i < wordArray.length; i++) {
			if ("p".equals(partPatternArray[i])) {
				wordList.add(wordArray[i]);
				propertyList.add(partPatternArray[i]);
			} else {
				if (wordList != null && wordList.size() > 1 && propertyList != null && propertyList.size() > 1) {
					DyadPre pp = new DyadPre();
					pp.setArray(BusinessUtil.getStringFromListBySeparator(wordList, ","));
					pp.setPartPattern(BusinessUtil.getStringFromListBySeparator(propertyList, ","));
					pp.setType("p+p");
					rtn.add(pp);
					wordList = new ArrayList<>();
					propertyList = new ArrayList<>();
				} else {
					wordList = new ArrayList<>();
					propertyList = new ArrayList<>();
				}
			}
		}
		return rtn;
	}

	/**
	 * 替换词语和拆分词语替换
	 * 
	 */
	private Map<String, String> replaceVocab(Map<String, Map<String, String>> replaceMap, String[] wordArray,
			String[] partPatternArray) {
		Map<String, String> rtn = new HashMap<>();
		for (int i = 0; i < wordArray.length; i++) {
			if (replaceMap.get(partPatternArray[i]) != null) {
				Map<String, String> replace = replaceMap.get(partPatternArray[i]);
				if (replace.get(wordArray[i]) != null) {
					String[] result = replace.get(wordArray[i]).split("\t");
					wordArray[i] = result[0];
					partPatternArray[i] = result[1];
				}
			}
		}
		rtn.put("array", BusinessUtil.getStringFromListBySeparator(CollectionUtil.getListByArray(wordArray), ","));
		rtn.put("partPattern",
				BusinessUtil.getStringFromListBySeparator(CollectionUtil.getListByArray(partPatternArray), ","));
		return rtn;
	}
	/**
	 * 判断是否符合含有该类属性
	 * 
	 * @param partPattern
	 * @param string
	 * @return
	 */

	private boolean checkProperty(String partPattern, String type) {
		String[] types = type.split(",");
		for (String property : types) {
			if ("o".equals(property) && !partPattern.contains("," + property + ",") && !partPattern.contains(",oa,")) {
				return false;
			} else if (!partPattern.contains("," + property + ",")) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 正常抽取si+de,s+de 先要抽取单个de,再抽取多个进行校验(抽取时,全部抽取在之后进行校验) de1,o,de2,de3,s, --->
	 * de1,s de2,s de3,s de1,de2,de3,s
	 * 
	 * @param type
	 * @return
	 */
	private List<DyadPre> extractDe(String type, String[] wordArray, String[] partPatternArray) {
		List<String> wordList = new ArrayList<>();
		List<String> propertyList = new ArrayList<>();
		List<DyadPre> rtn = new ArrayList<>();
		for (int i = 0; i < wordArray.length; i++) {
			if ("de".equals(partPatternArray[i]) || type.equals(partPatternArray[i])) {
				wordList.add(wordArray[i]);
				propertyList.add(partPatternArray[i]);
			}
		}
		if (wordList.size() > 0 && propertyList.size() > 0) {
			// 抽取所有的de和s,de和si 个数>2的时候才会出现需要单独抽取整个的二元组
			if (wordList.size() > 2) {
				DyadPre all = new DyadPre();
				all.setArray(BusinessUtil.getStringFromListBySeparator(wordList, ","));
				all.setPartPattern(BusinessUtil.getStringFromListBySeparator(propertyList, ","));
				all.setType(type + "+de");
				rtn.add(all);
			}
			// 抽取单个的de+s,de+si
			for (int i = 0; i < wordList.size(); i++) {
				String word = wordList.get(i);
				String property = propertyList.get(i);
				for (int j = i + 1; j < wordList.size(); j++) {
					if (!property.equals(propertyList.get(j))) {
						DyadPre pre = new DyadPre();
						pre.setArray("," + word + "," + wordList.get(j) + ",");
						pre.setPartPattern("," + property + "," + propertyList.get(j) + ",");
						pre.setType(type + "+de");
						rtn.add(pre);
					}
				}
			}
		}
		return rtn;
	}
	/**
	 * 连续从控制台获取症状来测试，直到输入“exit”结束
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		SymptomCheck sc = new SymptomCheck();

		System.out.println("请输症状：");
		Scanner s = new Scanner(System.in);
		String name;
		while (!(name = s.nextLine()).equals("exit")) {
			SymptomCheckResultUtil.printResult(sc.check(name));
			System.out.println("请输症状：");
		}
		s.close();

	}
}
